import json
import socket
import threading
from json import JSONDecodeError

from PyQt5.QtCore import pyqtSignal, QObject

from common.utils import decode_data
from models.chat_models import ChatRoom

CODE_MSG_HISTORY = 0
CODE_NEW_MSG = 1
CODE_CLIENT_LIST = 2
CODE_NOTICE = 4


class ChatRoomClient(QObject):
    BUFFER_SIZE = 4096
    on_msg_recv_signal = pyqtSignal(int, object)

    def __init__(self, nick_name, on_msg_update_handler: callable):
        super().__init__()
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        # self.client_socket.bind(("", 8002))
        self.nick_name = nick_name
        self.on_msg_recv_signal.connect(on_msg_update_handler)

        self.chat_room: ChatRoom = None
        self.running = False

    def __recv_msg_forever(self):
        if self.chat_room is None:
            return

        try:
            server = (self.chat_room.ip, self.chat_room.port)
            # 连接超时时间为2000ms
            self.client_socket.settimeout(2)
            
            self.client_socket.connect(server)

            # 后边的消息都可以一直等待
            self.client_socket.settimeout(None)
            self.running = True
            # 首先先把昵称发送给服务器
            self.client_socket.send(f"{self.nick_name}".encode())
            """
            接收消息
            :return:
            """
            while self.running:
                recv_data = self.client_socket.recv(self.BUFFER_SIZE)

                recv_msg = decode_data(recv_data)

                try:
                    # 有新的数据来了
                    json_obj = json.loads(recv_msg)
                    # 分别获取code, msg, data
                    code = json_obj["code"]
                    msg = json_obj["msg"]
                    data = json_obj["data"]
                    # 通知聊天室，有新的消息来了
                    print("收到消息：", code, msg)
                    self.on_msg_recv_signal.emit(code, data)
                except JSONDecodeError as e:
                    print("JSONDecodeError: ", e)
                    print("error----------------------json start")
                    print(recv_msg)
                    print("error----------------------json end")
        except ConnectionAbortedError as e:
            print("中止连接!", e)
        except socket.gaierror as e:
            print("连接错误!", e)
            self.on_msg_recv_signal.emit(100, f"服务器地址格式错误: {self.chat_room.ip}:{self.chat_room.port} \n错误消息: {str(e)}")
        except (TimeoutError, socket.timeout) as e:
            print("连接超时!", e)
            self.on_msg_recv_signal.emit(100, f"服务器连接超时\n请确认该服务器是否在运行: {self.chat_room.ip}:{self.chat_room.port} \n错误消息: {str(e)}")
        finally:
            if self.client_socket is not None:
                self.client_socket.close()
                self.client_socket = None

    def enter(self, chat_room: ChatRoom):
        self.chat_room = chat_room
        # 开启子线程，用来接收服务器发送的消息
        t = threading.Thread(target=self.__recv_msg_forever)
        t.daemon = True
        t.start()

    def exit(self):
        self.running = False
        if self.client_socket is not None and self.client_socket.fileno() != -1:
            self.client_socket.close()
            self.client_socket = None

    def send(self, text: str):
        self.client_socket.send(text.encode("UTF-8"))
